#include "stdafx.h"  
//#define BOOST_TEST_MODULE ASTAR_TEST
#include <boost/test/unit_test.hpp> 
#include "test_context.h"

using namespace boost::unit_test;
using namespace test;
using namespace graph;
using namespace graph::details;

graph::global_data_t graph::global::global_;
boost::shared_ptr<test_context_t> test_context;

//____________________________________________________________________________//

void cell_grid_test(graph::point_t p_to_test)
{   
   BOOST_TEST_CHECKPOINT( "Testing grid at test point: " << p_to_test.lat_ << " lat " << p_to_test.lon_ << " lon " );
   lat_lon_t cur_grad_per_cell = graph::details::grad_per_cell_traits_t<graph::details::d2>::value();
   //size_t factor = 1;
   //testing with different grid steps
   //for(factor = 1; factor <= 3; ++factor) //iterating over enum delta
   {
      //BOOST_TEST_CHECKPOINT( "Delta = " << factor);
      lat_lon_t little = cur_grad_per_cell / 2;
      cell_id_t id_test = graph_metadata_t::get_cell_id<d2>(p_to_test);
      cell_id_t prev_id_test = id_test;
      point_pair_t test_pp = graph_metadata_t::get_cell_rect<d2>(id_test);
      BOOST_TEST_CHECKPOINT( "checking if test point is in founded cell" );
      if (  !(p_to_test.lat_ >= test_pp.first.lat_) || 
            !(p_to_test.lon_ >= test_pp.first.lon_) ||
            !(p_to_test.lat_ <= test_pp.second.lat_) ||
            !(p_to_test.lon_ <= test_pp.second.lon_) 
         )
      {
         int a = 0; ++a;
         std::cout << "fail" << std::endl;
      }
      BOOST_REQUIRE( p_to_test.lat_ >= test_pp.first.lat_ );
      BOOST_REQUIRE( p_to_test.lon_ >= test_pp.first.lon_ );
      BOOST_REQUIRE( p_to_test.lat_ <= test_pp.second.lat_ );
      BOOST_REQUIRE( p_to_test.lon_ <= test_pp.second.lon_ );
      p_to_test.lon_ = test_pp.first.lon_; //left low corner of cell
      p_to_test.lat_ = test_pp.first.lat_;
      BOOST_TEST_CHECKPOINT( "comparing id of point in the center of cell, which test point belongs with id of test point cell" );
      id_test = graph_metadata_t::get_cell_id<d2>(point_t(p_to_test.lat_ + little, p_to_test.lon_ + little));      
      BOOST_REQUIRE( prev_id_test == id_test );
      if (p_to_test.lat_ > 0 || p_to_test.lon_  > 0)
      {
         int a = 0;
         a++;
      }
      
      BOOST_TEST_CHECKPOINT( "moving test point up 10 times" );
      for(int i = 0; i < 10; ++i)
      {
         BOOST_TEST_CHECKPOINT( "moving test point one cell up" );
         p_to_test.lat_ += cur_grad_per_cell;
         id_test = graph_metadata_t::get_cell_id<d2>(point_t(p_to_test.lat_ + little, p_to_test.lon_ + little));
         BOOST_TEST_CHECKPOINT( "new id x: " << id_test.first << " y: " << id_test.second );
         BOOST_REQUIRE( id_test.first == prev_id_test.first && (id_test.second - 1) == prev_id_test.second );
         prev_id_test = id_test;
      }
      BOOST_TEST_CHECKPOINT( "moving test point right 10 times" );
      for(int i = 0; i < 10; ++i)
      {
         BOOST_TEST_CHECKPOINT( "moving test point one cell right" );
         p_to_test.lon_ += cur_grad_per_cell;
         id_test = graph_metadata_t::get_cell_id<d2>(point_t(p_to_test.lat_ + little, p_to_test.lon_ + little));
         BOOST_TEST_CHECKPOINT( "new id x: " << id_test.first << " y: " << id_test.second);
         BOOST_REQUIRE( (id_test.first - 1) == prev_id_test.first && id_test.second == prev_id_test.second );
         prev_id_test = id_test;
      }
      
      BOOST_TEST_CHECKPOINT( "moving test point right and up 10 times (diagonaly)" );
      for(int i = 0; i < 10; ++i)
      {
         BOOST_TEST_CHECKPOINT( "moving test point one cell right" );
         p_to_test.lat_ += cur_grad_per_cell;
         p_to_test.lon_ += cur_grad_per_cell;
         id_test = graph_metadata_t::get_cell_id<d2>(point_t(p_to_test.lat_ + little, p_to_test.lon_ + little));
         BOOST_TEST_CHECKPOINT( "new id x: " << id_test.first << " y: " << id_test.second);
         BOOST_REQUIRE( (id_test.first - 1) == prev_id_test.first && (id_test.second - 1) == prev_id_test.second );
         prev_id_test = id_test;
      }
   }
}

//____________________________________________________________________________//

void min_heap_test()
{
   graph::algorithm::min_heap_t heap;
   heap.insert(9, 9);
   heap.insert(10, 10);
   heap.insert(8, 8);
   heap.insert(1, 1);
   heap.insert(3, 3);
   heap.insert(2, 2);
   heap.extract_min();
   heap.insert(4, 4);
   heap.insert(11, 11);
   heap.insert(7, 7);
   heap.extract_min();
   heap.insert(12, 12);
   heap.dec_key_by_id(0, 12);
   heap.insert(5, 5);
   heap.insert(6, 6);
   BOOST_REQUIRE(heap.has_key(11));
   BOOST_REQUIRE(heap.has_key(8));
   BOOST_REQUIRE(heap.has_key(3));
   
   BOOST_REQUIRE(12 == heap.extract_min());
   BOOST_REQUIRE(3 == heap.extract_min());
   BOOST_REQUIRE(4 == heap.extract_min());
   BOOST_REQUIRE(5 == heap.extract_min());
   BOOST_REQUIRE(6 == heap.extract_min());
   BOOST_REQUIRE(7 == heap.extract_min());
   BOOST_REQUIRE(8 == heap.extract_min());
   BOOST_REQUIRE(9 == heap.extract_min());
   BOOST_REQUIRE(10 == heap.extract_min());
   
   heap.insert(13, 13);
   heap.dec_key_by_id(-1, 13);
   heap.insert(17, 17);
   heap.insert(11, 11);
   
   BOOST_REQUIRE(13 == heap.extract_min());
   BOOST_REQUIRE(11 == heap.extract_min());
   BOOST_REQUIRE(11 == heap.extract_min());
   BOOST_REQUIRE(17 == heap.extract_min());
   
   BOOST_REQUIRE(heap.empty());
   
   heap.insert(13, 13);
   heap.insert(17, 17);
   heap.insert(11, 11);
   heap.dec_key_by_id(-1, 13);
   
   BOOST_REQUIRE(13 == heap.extract_min());
   BOOST_REQUIRE(11 == heap.extract_min());
   BOOST_REQUIRE(17 == heap.extract_min());
}

//____________________________________________________________________________//

//____________________________INIT TEST SUITE SECTION______________________________________//

test_suite* init_unit_test_suite( int argc, char* argv[] ) 
{
   if (argc < 2)
   {
      std::cerr << "Please supply file name with graph as first argument" << std::endl;
      std::cerr << "and count of test runs as second argument" << std::endl;
      exit(-1);
   }   
   framework::master_test_suite().p_name.value = "Miscellaneous test suite";
   test_context = boost::shared_ptr<test_context_t>(new test_context_t(argv[1]));
   boost::unit_test::unit_test_log.set_stream( test_context->get_test_log() );
   boost::unit_test::unit_test_log.set_threshold_level( boost::unit_test::log_messages );
   size_t test_count = boost::lexical_cast<size_t>(argv[2]);
   srand(time(0)); //lat_lon_t max = -MAX_FLOAT;
   //for(size_t i = 0; i < test_count; ++i)
   {
      point_t test_point( 
         ((lat_lon_t)((rand() << 16 | rand() ) % 180000))/1000 - 90,
         ((lat_lon_t)((rand() << 16 | rand() ) % 360000))/1000 - 180
      );
      framework::master_test_suite().
            add( BOOST_TEST_CASE( boost::bind(&cell_grid_test, test_point) ) );
   } 
   framework::master_test_suite().add( BOOST_TEST_CASE(min_heap_test ) );

   return 0;
}

//____________________________________________________________________________//
